#include "FPM383C.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "bflb_mtimer.h"
#include "bflb_dma.h"
#include "bflb_uart.h"
#include "bflb_gpio.h"
#include "log.h"

//控制模块LED灯颜色
uint8_t PS_BlueLEDBuf[16] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x07,0x3C,0x03,0x01,0x01,0x00,0x00,0x49};
uint8_t PS_RedLEDBuf[16] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x07,0x3C,0x02,0x04,0x04,0x02,0x00,0x50};
uint8_t PS_GreenLEDBuf[16] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x07,0x3C,0x02,0x02,0x02,0x02,0x00,0x4C};

//休眠指令-设置传感器进入休眠模式
uint8_t PS_SleepBuf[12] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x33,0x00,0x37};

//清空指纹库-删除 flash 数据库中所有指纹模板。
uint8_t PS_EmptyBuf[12] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x0D,0x00,0x11};

//取消指令-取消自动注册模板和自动验证指纹。如表 2-1 中加密等级设置为 0 或 1 情况下支持此功能
uint8_t PS_CancelBuf[12] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x30,0x00,0x34};

//自动注册模板-一站式注册指纹，包含采集指纹、生成特征、组合模板、存储模板等功能。加密等级设置为 0 或 1 情况下支持此功能。
uint8_t PS_AutoEnrollBuf[17] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x08,0x31,'\0','\0',0x04,0x00,0x16,'\0','\0'}; 

// 验证用获取图像-验证指纹时，探测手指，探测到后录入指纹图像存于图像缓冲区。返回确认码表示：录入成功、无手指等。
uint8_t PS_GetImageBuf[12] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x01,0x00,0x05};

//生成特征值-将图像缓冲区中的原始图像生成指纹特征文件存于模板缓冲区
uint8_t PS_GetCharBuf[13] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x04,0x02,0x01,0x00,0x08};

//搜索指纹-以模板缓冲区中的特征文件搜索整个或部分指纹库。若搜索到，则返回页码。加密等级设置为 0 或 1 情况下支持
uint8_t PS_SearchBuf[17] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x08,0x04,0x01,0x00,0x00,0xFF,0xFF,0x02,0x0C};

//删除模板-删除 flash 数据库中指定 ID 号开始的N 个指纹模板
uint8_t PS_DeleteBuf[16] = {0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x07,0x0C,'\0','\0',0x00,0x01,'\0','\0'};

//设置名为fpm383c_uart的外设句柄,用来执行串口指令的发送
struct bflb_device_s *fpm383c_uart;

//指纹ID和验证指纹的分数
uint16_t pageID,score;

//USART串口接收缓冲数组
uint8_t USART_ReceiveBuf[20];

//主循环状态标志位
uint8_t ScanStatus = 0;

/**
 * @brief 获取状态
 * 
 * @param Timeout 
 */
void FPM383C_ReceiveData(uint16_t Timeout)
{
  uint8_t i = 0;
  // 检测缓冲区是否有数据
  while(bflb_uart_rxavailable(fpm383c_uart) == 0 && (--Timeout))
  {
    bflb_mtimer_delay_ms(1);
  }
  // 轮询fpm383c_uart接收到的字符
  while(bflb_uart_rxavailable(fpm383c_uart) > 0)
  {
    bflb_mtimer_delay_ms(2);
	// 获取数据并放入缓冲数组
    USART_ReceiveBuf[i++] = bflb_uart_getchar(fpm383c_uart);
    if(i > 15) break; 
  }
}

/// @brief 初始化FPM383C指纹模块
void FPM383C_Init(){
	// 声明 gpio句柄
    struct bflb_device_s* gpio;
	// FPM383C 模块默认波特率为 57600 
    struct bflb_uart_config_s cfg = {
        .baudrate = 57600,
        .data_bits = UART_DATA_BITS_8,
        .stop_bits = UART_STOP_BITS_1,
        .parity = UART_PARITY_NONE,
       	.flow_ctrl = UART_FLOWCTRL_NONE,
        .rx_fifo_threshold = 7,
        .tx_fifo_threshold = 7
    };

	// 初始化FPM383C指纹模块UART
    gpio = bflb_device_get_by_name("gpio");
    fpm383c_uart = bflb_device_get_by_name("uart1");

    //将GPIO_23和GPIO_24设置为TX和RX
    bflb_gpio_uart_init(gpio, GPIO_PIN_23, GPIO_UART_FUNC_UART1_TX);
    bflb_gpio_uart_init(gpio, GPIO_PIN_24, GPIO_UART_FUNC_UART1_RX);

    bflb_uart_init(fpm383c_uart, &cfg);
}

/// @brief USART串口发送数据
/// @param length 发送数组长度
/// @param FPM383C_DataBuf 需要发送的功能数组
void FPM383C_SendData(int length,uint8_t FPM383C_DataBuf[])
{

	for(int i = 0;i<length;i++)
	{
        bflb_uart_put(fpm383c_uart,(uint8_t *)&FPM383C_DataBuf[i], 1);
	}
}

/// @brief 发送休眠指令 确认码=00H 表示休眠设置成功。确认码=01H 表示休眠设置失败。
/// @param  
void FPM383C_Sleep(void)
{
	FPM383C_SendData(12,PS_SleepBuf);
}

/// @brief 验证用获取图像
/// @param timeout 接收数据的超时时间
/// @return 确认码
uint8_t FPM383C_GetImage(uint32_t timeout)
{
	uint8_t tmp;
	FPM383C_SendData(12,PS_GetImageBuf);
	FPM383C_ReceiveData(timeout);
	tmp = (USART_ReceiveBuf[6] == 0x07 ? USART_ReceiveBuf[9] : 0xFF);
	memset(USART_ReceiveBuf,0xFF,sizeof(USART_ReceiveBuf));
	return tmp;
}

/// @brief 将图像缓冲区中的原始图像生成指纹特征文件存于模板缓冲区。
/// @param timeout 接收数据的超时时间
/// @return 确认码
uint8_t FPM383C_GenChar(uint32_t timeout)
{
	uint8_t tmp;
	FPM383C_SendData(13,PS_GetCharBuf);
	FPM383C_ReceiveData(timeout);
	tmp = (USART_ReceiveBuf[6] == 0x07 ? USART_ReceiveBuf[9] : 0xFF);
	memset(USART_ReceiveBuf,0xFF,sizeof(USART_ReceiveBuf));
	return tmp;
}

/// @brief 发送搜索指纹指令
/// @param timeout 接收数据的超时时间
/// @return 确认码
uint8_t FPM383C_Search(uint32_t timeout)
{
	FPM383C_SendData(17,PS_SearchBuf);
	FPM383C_ReceiveData(timeout);
	return (USART_ReceiveBuf[6] == 0x07 ? USART_ReceiveBuf[9] : 0xFF);
}

/// @brief 删除指定指纹指令
/// @param pageID 需要删除的指纹ID号
/// @param timeout 接收数据的超时时间
/// @return 确认码
uint8_t FPM383C_Delete(uint16_t pageID,uint32_t timeout)
{
	uint8_t tmp;
	PS_DeleteBuf[10] = (pageID>>8);
	PS_DeleteBuf[11] = (pageID);
	PS_DeleteBuf[14] = (0x15+PS_DeleteBuf[10]+PS_DeleteBuf[11])>>8;
	PS_DeleteBuf[15] = (0x15+PS_DeleteBuf[10]+PS_DeleteBuf[11]);
	FPM383C_SendData(16,PS_DeleteBuf);
	FPM383C_ReceiveData(timeout);
	tmp = (USART_ReceiveBuf[6] == 0x07 ? USART_ReceiveBuf[9] : 0xFF);
	memset(USART_ReceiveBuf,0xFF,sizeof(USART_ReceiveBuf));
	return tmp;
}

/// @brief 清空指纹库
/// @param timeout 接收数据的超时时间
/// @return 确认码
uint8_t FPM383C_Empty(uint32_t timeout)
{
	uint8_t tmp;
	FPM383C_SendData(12,PS_EmptyBuf);
	FPM383C_ReceiveData(timeout);
	tmp = (USART_ReceiveBuf[6] == 0x07 ? USART_ReceiveBuf[9] : 0xFF);
	memset(USART_ReceiveBuf,0xFF,sizeof(USART_ReceiveBuf));
	return tmp;
}

/// @brief 发送控制灯光指令
/// @param PS_ControlLEDBuf 不同颜色的协议数据
/// @param timeout 接收数据的超时时间
/// @return 确认码
uint8_t FPM383C_ControlLED(uint8_t PS_ControlLEDBuf[],uint32_t timeout)
{
	uint8_t tmp;
	FPM383C_SendData(16,PS_ControlLEDBuf);
	FPM383C_ReceiveData(timeout);
	tmp = (USART_ReceiveBuf[6] == 0x07 ? USART_ReceiveBuf[9] : 0xFF);
	memset(USART_ReceiveBuf,0xFF,sizeof(USART_ReceiveBuf));
	return tmp;
}

/// @brief 验证指纹是否注册
/// @param  
void FPM383C_Identify(void)
{
	if(FPM383C_GetImage(2000) == 0x00)
	{
		if(FPM383C_GenChar(2000) == 0x00)
		{
			struct bflb_device_s *led = bflb_device_get_by_name("gpio");
			if(FPM383C_Search(2000) == 0x00)
			{
				score = (int)((USART_ReceiveBuf[10] << 8) + USART_ReceiveBuf[11]);
				LOG_E("解锁成功 指纹ID：%d\r\n",(int)score);
				FPM383C_ControlLED(PS_GreenLEDBuf,1000);
		
				bflb_gpio_init(led, GPIO_PIN_14, GPIO_OUTPUT);
				bflb_gpio_set(led, GPIO_PIN_14);
				bflb_mtimer_delay_ms(1000);
				bflb_gpio_reset(led, GPIO_PIN_14);
				// 重置接收数据缓存
				memset(USART_ReceiveBuf,0xFF,sizeof(USART_ReceiveBuf));
				return;
			}else{
				LOG_E("解锁失败\r\n");
				bflb_gpio_init(led, GPIO_PIN_12, GPIO_OUTPUT);
				bflb_gpio_set(led, GPIO_PIN_12);
				bflb_mtimer_delay_ms(1000);
				bflb_gpio_reset(led, GPIO_PIN_12);
				// 重置接收数据缓存
				memset(USART_ReceiveBuf,0xFF,sizeof(USART_ReceiveBuf));
				return;
			}
		}
	}
}

/// @brief 自动注册
/// @param pageID 输入需要注册的指纹ID号，取值范围0—59
/// @param timeout 设置注册指纹超时时间，因为需要按压四次手指，建议大于10000（即10s）
void FPM383C_Enroll(uint16_t pageID,uint16_t timeout)
{
	LOG_E("注册指纹ID: %d\r\n", pageID);
	PS_AutoEnrollBuf[10] = (pageID>>8);
	PS_AutoEnrollBuf[11] = (pageID);
	PS_AutoEnrollBuf[15] = (0x54+PS_AutoEnrollBuf[10]+PS_AutoEnrollBuf[11])>>8;
	PS_AutoEnrollBuf[16] = (0x54+PS_AutoEnrollBuf[10]+PS_AutoEnrollBuf[11]);
	FPM383C_SendData(17,PS_AutoEnrollBuf);
	FPM383C_ReceiveData(timeout);
	if(USART_ReceiveBuf[9] == 0x00)
	{
		LOG_E("指纹注册完成\r\n");
		// 亮绿灯2秒
		FPM383C_ControlLED(PS_GreenLEDBuf,2000);
		// 重置接收数据缓存
		memset(USART_ReceiveBuf,0xFF,sizeof(USART_ReceiveBuf));
		return;
	}
	else if(timeout == 0)
	{
		// 超时取消注册
		FPM383C_SendData(12,PS_CancelBuf);
		bflb_mtimer_delay_ms(50);
		// 重置接收数据缓存
		memset(USART_ReceiveBuf,0xFF,sizeof(USART_ReceiveBuf));
	}
	// 亮红灯2秒
	FPM383C_ControlLED(PS_RedLEDBuf,2000);
}
